﻿//--------------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="RegistrationSteps.cs">
//     Copyright © 2010 Oli Francis
//     This source code is subject to the terms and conditions of the MIT license. A copy of the license can be found in the license.txt 
//     file at the root of this distribution. By using this source code in any fashion, you are agreeing to be bound by the terms of the MIT License. 
//     You must not remove this notice from the software.
// </copyright>
// <author>Oli</author>
//-------------------------------------------------------------------------------------------------------------------------------------------------------

namespace TeamBrain.Tests.StepDefinitions
{
    using System;
    using System.Web.Mvc;

    using Moq;

    using NUnit.Framework;

    using TeamBrain.Domain.Model;
    using TeamBrain.Domain.Services.Exceptions;
    using TeamBrain.Domain.Services.Registration;
    using TeamBrain.Tests.Utilities;
    using TeamBrain.Web.Controllers;
    using TeamBrain.Web.Utilities;

    using TechTalk.SpecFlow;

    /// <summary>
    /// Defines methods that bind to the scenario steps for the Registration feature
    /// </summary>
    [Binding]
    [StepScope(Feature = "Registration")]
    public class RegistrationSteps
    {
        private readonly Mock<IRegistrationService> registrationService = new Mock<IRegistrationService>();
        private ActionResult actionResult;

        [BeforeScenario]
        public void BeforeScenario()
        {
            ScenarioContext.Current["FirstName"] = String.Empty;
            ScenarioContext.Current["LastName"] = String.Empty;
            ScenarioContext.Current["EmailAddress"] = String.Empty;
            ScenarioContext.Current["Password"] = String.Empty;
            ScenarioContext.Current["PasswordConfirmation"] = String.Empty;
        }

        #region Arrange

        [Given(@"I don't have an account")]
        public void GivenIDonTHaveAnAccount()
        {
        }
        
        [Given(@"I have entered a password")]
        public void GivenIHaveEnteredAPassword()
        {
            ScenarioContext.Current["Password"] = "CheeseFace!";
        }

        [Given(@"I have made a mistake in confirming the password")]
        public void GivenIHaveMadeAMistakeInConfirmingThePassword()
        {
            ScenarioContext.Current["PasswordConfirmation"] = "CheesyIdeaJames!";
        }

        [Given(@"the password length is less than 5 characters")]
        public void GivenThePasswordLengthIsLessThan6Characters()
        {
            ScenarioContext.Current["Password"] = "Pie!";
        }

        [Given(@"the password length is more than 20 characters")]
        public void GivenThePasswordLengthIsMoreThan20Characters()
        {
            ScenarioContext.Current["Password"] = "ABCDEFGHIJKLMNOPQRSTU!";
        }

        [Given(@"the password doesn't contain at least one number or special character")]
        public void GivenThePasswordDoesnTContainAtLeastOneNumberOrSpecialCharacter()
        {
            ScenarioContext.Current["Password"] = "Simple";
        }

        [Given(@"I have entered an email that is already registered")]
        public void GivenIHaveEnteredAnEmailThatIsAlreadyRegistered()
        {
            this.registrationService.Setup(s => s.RegisterNewUser(It.IsAny<User>())).Throws(
                new EmailAlreadyRegisteredException());
        }
        
        [Given(@"I have completed the registration form successfully")]
        public void GivenIHaveCompletedTheRegistrationFormSuccessfully()
        {
            ScenarioContext.Current["EmailAddress"] = "test@test.com";
            ScenarioContext.Current["FirstName"] = "Oli";
            ScenarioContext.Current["LastName"] = "Francis";
            ScenarioContext.Current["Password"] = "Ju1ce!";
            ScenarioContext.Current["PasswordConfirmation"] = "Ju1ce!";
        }
        
        #endregion

        #region Act

        [When(@"I follow the sign up link")]
        public void WhenIFollowTheSignUpLink()
        {
            var controller = new RegistrationController(this.registrationService.Object);
            this.actionResult = controller.Index();
        }
        
        [When(@"I hit save")]
        public void WhenIHitSave()
        {
            var controller = new RegistrationController(this.registrationService.Object);

            var user = new User
            {
                FirstName = (string)ScenarioContext.Current["FirstName"],
                LastName = (string)ScenarioContext.Current["LastName"],
                EmailAddress = (string)ScenarioContext.Current["EmailAddress"],
                Password = (string)ScenarioContext.Current["Password"]
            };

            var passwordConfirmation = (string)ScenarioContext.Current["PasswordConfirmation"];

            this.actionResult = controller.CallWithModelValidation(c => c.Index(user, passwordConfirmation), user);
        }

        #endregion

        #region Assert

        [Then(@"I see the registration form")]
        public void ThenISeeTheRegistrationForm()
        {
            var viewResult = this.actionResult as ViewResult;
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Index", viewResult.ViewName);
        }

        [Then(@"I see a validation error against (.*)")]
        public void ThenISeeAValidationErrorAgainstX(string field)
        {
            var view = this.actionResult as ViewResult;
            Assert.IsNotNull(view);
            Assert.AreEqual("Index", view.ViewName);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField(field.ToPascalCase()));
        }

        [Then(@"an email is sent to my email address")]
        public void ThenAnEmailIsSentToMyEmailAddress()
        {
            this.registrationService.Verify(s => s.RegisterNewUser(It.IsAny<User>()));
        }

        [Then(@"I see a confirmation page telling me to check my inbox")]
        public void ThenISeeAConfirmationPageTellingMeToCheckMyInbox()
        {
            var result = this.actionResult as RedirectToRouteResult;
            Assert.IsNotNull(result);
        }

        #endregion
    }
}
